import numpy as np
import json
import matplotlib.pyplot as plt

def load_data():
    # 读入训练数据
    datafile = 'housing.data'
    data = np.fromfile(datafile,sep=' ')

    # print(data)
    # 对数据进行特征命名
    feature_names = [ 'CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE','DIS',
                     'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV' ]
    # 确定特征的数量
    feature_num = len(feature_names)

    # 将一维数据转化为二维数据
    data = data.reshape([data.shape[0]//feature_num,feature_num])

    # 划分测试集和训练集
    ratio = 0.8
    offset = int(data.shape[0]*ratio)
    training_data = data[:offset]
    # print(training_data.shape)

    # 计算train数据集的最大值，最小值
    maximums,minimums = training_data.max(axis=0),training_data.min(axis=0)
    # 对数据进行归一化处理
    for i in range(feature_num):
        data[:,i] = (data[:,i] - minimums[i])/(maximums[i] - minimums[i])
    # 训练集和测试集的划分比例
    training_data = data[:offset]
    test_data = data[offset:]
    return training_data,test_data

# 构建神经网络类
class Network(object):
    def __init__(self,num_of_weights):
        # 随机产生w的初始化
        # 为了保持程序每次运行结果的一致性
        # 此处设置固定的随机数种子
        np.random.seed(0)
        self.w = np.random.randn(num_of_weights,1)
        self.b = 0.

    def forward(self,x):
        z = np.dot(x,self.w) + self.b
        return z

    def loss(self,z,y):
        error = z - y
        cost = error * error
        cost = np.mean(cost)
        return cost

    def gradient(self,x, y):
        z = self.forward(x)
        gradient_w = (z - y) * x
        gradient_w = np.mean(gradient_w,axis=0)
        gradient_w = gradient_w[:,np.newaxis]
        gradient_b = (z - y)
        gradient_b = np.mean(gradient_b)
        return gradient_w,gradient_b

    def update(self,gradient_w,gradient_b,eta = 0.01):
        self.w = self.w - eta * gradient_w
        self.b = self.b - eta * gradient_b

    def train(self,x,y,iterations=100,eta=0.01):
        losses = []
        for i in range(iterations):
            z = self.forward(x)
            L = self.loss(z,y)
            gradient_w,gradient_b = self.gradient(x,y)
            self.update(gradient_w,gradient_b,eta)
            losses.append(L)
            if (i+1) % 10 == 0:
                print('iter {},w {},b {}, loss {}'.format(i,self.w,self.b,L))
        return losses


# 获取数据
train_data,test_data = load_data()
x = train_data[:,:-1]
y = train_data[:,-1:]
# 创建网络
net = Network(13)
num_iterations = 1000

# 启动训练
losses = net.train(x,y,iterations=num_iterations,eta=0.01)

# 画出损失函数的变化趋势
plot_x = np.arange(num_iterations)
plot_y = np.array(losses)
plt.plot(plot_x,plot_y)
plt.show()

